Challenge: SantaCloud (December 2025)
Code: INTIGRITI-LX72F3Y2
Asset: https://santacloud.intigriti.io
Severity: High (chained issues)
Status: Archived / Resolved
Summary
A chain of low-hanging but high-impact issues allowed complete compromise of the application:
- Sensitive backup file exposed via
robots.txt - Hardcoded admin credentials and secrets in
composer.json~ - Successful login as
elf_supervisor(admin) - IDOR in the Notes API (
/api/notes/{id}) that completely ignored user ownership
The result: any unauthenticated visitor could discover the backup, log in as admin, and read every private note belonging to every user — including other participants’ flags.
In Simple Terms
- The site told everyone where to look for secrets (
robots.txt). - A backup file sitting in the web root contained the admin username, password, and other secrets in plain text.
- Once logged in as admin, the “notes” feature trusted whatever note ID you asked for — no check whether the note actually belonged to you.
- Changing the note ID in the API request let us read anyone else’s private data.
Reconnaissance
Step 1: robots.txt Disclosure
Visiting the root revealed a robots.txt that pointed to a suspicious backup file:
GET /robots.txtThe file contained:
/composer.json~Step 2: Backup File Leak
Direct access to the backup file was possible without authentication:
https://santacloud.intigriti.io/composer.json~
The file contained hardcoded credentials:
"admin-access": { "username": "elf_supervisor", "password": "CookiesAndMilk1337", "api-endpoint": "http://santacloud.intigriti.io/login"},"env": { "secret": "INTIGRITI{019b118e-e563-7348", "ttl": 3600}This single file gave us everything needed for account takeover.
Exploitation
1. Admin Account Takeover
Using the leaked credentials:
- Username:
elf_supervisor - Password:
CookiesAndMilk1337
We successfully authenticated as an administrator.
2. IDOR in the Notes API
After logging in, we navigated to the user profile and opened the “Internal Notes” section.
Intercepting the request when editing a note revealed:
GET /api/notes/{note-id}Critical flaw: The endpoint accepted any note-id and returned the note without verifying ownership.
Proof-of-Concept Request:
GET /api/notes/3Host: santacloud.intigriti.ioCookie: session=...Response:
{ "success": true, "note": { "id": 3, "user_id": 1, "title": "The Secret Key", "content": "INTIGRITI{019b118e-e563-7348-a377-c1e5f944bb46}", "is_private": true }}Evidence of IDOR:
- Our logged-in user had
user_id = 2 - The note returned belonged to
user_id = 1 - No authorization check existed on the server
By simply changing the note ID, we could enumerate and read private notes (and flags) from all users.
Impact
| Aspect | Impact |
|---|---|
| Confidentiality | Full access to all users’ private notes |
| Authentication | Complete admin account compromise |
| Authorization | Total bypass via IDOR |
| Secrets | Hardcoded credentials and application secret exposed |
| Real-world risk | Any attacker could exfiltrate all private data |
This is a classic example of chained low-severity issues resulting in high-severity impact: information disclosure → credential leakage → broken access control.
Root Cause
- Backup files (
.~,.bak, etc.) were not excluded from public web access. - Hardcoded secrets were committed (and backed up) in application source files.
- Missing authorization on the
/api/notes/{id}endpoint — the API trusted the caller to only request their own notes. - Client-side trust — the frontend only showed notes belonging to the current user, but the backend performed no ownership validation.
Remediation
Immediate Actions
- Delete or restrict access to
composer.json~and any other backup files. - Remove sensitive paths from
robots.txt. - Rotate all exposed credentials and secrets immediately.
Code-Level Fixes
1. Prevent backup file exposure
# .htaccess or web server config<FilesMatch "\.(~|bak|old|swp)$"> Require all denied</FilesMatch>2. Never store secrets in source-controlled files Use environment variables or a proper secrets manager.
3. Fix the IDOR (proper authorization)
// Example server-side checkconst note = await db.notes.findById(noteId);if (!note || note.user_id !== currentUser.id) { return res.status(403).json({ error: "Forbidden" });}return res.json({ note });4. Add server-side ownership validation on all object retrieval endpoints.
Conclusion
This challenge demonstrated how a seemingly minor information disclosure (a backup file) can quickly escalate when combined with poor secret management and missing authorization checks.
The combination of:
- Publicly listed backup file
- Hardcoded admin credentials
- Unprotected object references in the API
…allowed complete compromise of user data.
Flag: INTIGRITI{019b118e-e563-7348-a377-c1e5f944bb46}
Reported on Intigriti as part of the December 2025 SantaCloud challenge (INTIGRITI-LX72F3Y2).
Challenge Link: https://santacloud.intigriti.io