DEV Community

Cover image for Lab: Finding a hidden GraphQL endpoint
tRavOndAtrACk
tRavOndAtrACk

Posted on

Lab: Finding a hidden GraphQL endpoint

Author: travondatrack
Date: 14/01/2026
Category: Pentest | Web | Security
Difficulty: PRACTITIONER
Tags: GraphQL


Mô tả

The user management functions for this lab are powered by a hidden GraphQL endpoint. You won't be able to find this endpoint by simply clicking pages in the site. The endpoint also has some defenses against introspection.

To solve the lab, find the hidden endpoint and delete carlos.

Link: https://portswigger.net/web-security/graphql/lab-graphql-find-the-endpoint


Phân tích vấn đề

Recon

  • Lab không expose endpoint GraphQL rõ ràng (không có /graphql, /graphiql, v.v.).
  • Ta cần thử các path phổ biến.
COMMON_GRAPHQL_PATHS = [
    "/api",
    "/graphql",
    "/api/graphql",
    "/v1/graphql",
    "/v2/graphql",
    "/gql"
]
Enter fullscreen mode Exit fullscreen mode

Khai thác

Bước 1: Scanning for hidden GraphQL endpoint

  • Viết script Python để tìm endpoint.
import requests

BASE_URL = "https://0a0a00d00322650a805644e4006800a4.web-security-academy.net"

# Cookie lấy từ request /login
COOKIES = {
    "session": "XHAvkzbOEaTNhOHFhW6sCjzHp1nRV6a1"
}

HEADERS = {
    "User-Agent": "Mozilla/5.0",
    "Accept": "application/json"
}

# Các endpoint hay gặp trong thực tế
COMMON_GRAPHQL_PATHS = [
    "/api",
    "/graphql",
    "/api/graphql",
    "/v1/graphql",
    "/v2/graphql",
    "/gql"
]

TEST_QUERY = "query{__typename}"

def is_graphql_endpoint(path):
    url = BASE_URL + path
    params = {"query": TEST_QUERY}

    try:
        r = requests.get(
            url,
            headers=HEADERS,
            cookies=COOKIES,
            params=params,
            timeout=5
        )

        if r.status_code == 200 and "__typename" in r.text:
            print(f"[+] GraphQL endpoint FOUND: {path}")
            print(r.text)
            return True
        else:
            print(f"[-] {path} -> Not GraphQL")

    except Exception as e:
        print(f"[!] {path} -> Error: {e}")

    return False


if __name__ == "__main__":
    print("[*] Scanning for hidden GraphQL endpoint...\n")

    for path in COMMON_GRAPHQL_PATHS:
        if is_graphql_endpoint(path):
            break
Enter fullscreen mode Exit fullscreen mode
  • Kết quả tìm được.

Bước 2: Bypass introspection defense

  • Thử gửi introspection query chuẩn

  • Server dùng regex đơn giản để block chuỗi "__schema{". GraphQL bỏ qua whitespace/newline, nhưng regex có thể không xử lý tốt

==> Bybass bằng \n

  • Sau khi có được schema, ta thấy có 1 mutation nguy hiểm "name": "deleteOrganizationUser".

  • Ta cần tìm id của carlos để xóa.

query {
  getUser(id: ...) {
    id
    username
  }
}
Enter fullscreen mode Exit fullscreen mode


Submit

  • Xóa tài khoản carlos thông qua deleteOrganizationUser.

==> DONE!

Top comments (0)