KYC Bypass Chain: Zero-Field Entity Passes Verification
What happened
Agent systematically tested all API endpoints without authentication and discovered multiple endpoints that process requests without any auth checks.
Impact
Unauthenticated attackers can access protected API functionality, potentially reading sensitive data and performing unauthorized operations.
Agent Trace
Good data gathered. I can see the app uses GraphQL at '/graphql' with origin checks and Rails '_████████' session cookies. HTTP history shows 53 captured requests. Now I'll plan two parallel tracks:
- Authenticated crawl → replay without session - login, discover all endpoints, strip cookies and test each
- Unauthenticated probe - common paths, GraphQL introspection, JS bundles, static assets, Next.js internals, Pusher auth, health checks
Both agents are running in parallel. Here's what's being tested:
| Agent | Focus | Status |
|---|---|---|
| task_0 - Advanced | Login with ORG 1 → crawl all sections → strip session cookies → replay every endpoint/GraphQL op unauthenticated | 🔄 Running |
| task_1 - Standard | Cold unauthenticated probe: health checks, Rails internals, Next.js paths, GraphQL introspection, Pusher auth, static assets, source maps | 🔄 Running |
Waiting for results - will resume automatically when agents complete.
Both agents are progressing well - no intervention needed.
- task_0: Successfully obtained fresh session via browser handover, verifying CSRF token before starting the strip-cookie replay sweep. On track.
- task_1: Already found the production Sentry release (full git SHA exposed in CSP), downloaded the 1.87MB JS bundle, confirmed source maps return 403, and is finishing up remaining path probes. Solid progress.
Continuing to wait for both to complete.
I'll start by following the mandatory steps: get workspace metadata, search for skills, and check existing files before beginning the unauthenticated probing.
Good context gathered. Now I'll start the comprehensive unauthenticated probing. I'll batch requests efficiently. Starting with metadata/health endpoints simultaneously:
Good first batch. Now continuing with status/version and Rails-specific endpoints:
KEY FINDING: '/version' returns '[REDACTED_BUILD]' publicly (HTTP 200) without auth! Now probing more endpoints:
Now testing sensitive config files and auth callback endpoints:
Interesting: '.env' blocked by AWS WAF (400), '/auth/auth0/callback' detects CSRF properly (redirects to failure). Now testing GraphQL unauthenticated (NO cookie) with Referer header:
GraphQL requires session cookie (returns 404 when unauthenticated even with Referer). Now testing GraphQL with QuickSwitchView and ProfileHome unauthenticated, plus webhook paths:
Now testing well-known endpoints, Pusher auth, and POSTing to webhook endpoints:
Pusher endpoints EXIST (403 without Referer). Let me test them with proper Referer but NO session cookie:
Now I'll fetch the main JS bundle from assets.████████.com to search for secrets, API keys, and internal URLs:
Key finding: Sentry release is a full git commit SHA '[REDACTED_HEX]'. Actual bundle is 'index-[REDACTED_HASH].js'. Let me download and analyze it:
Got the 1.87MB main bundle! Source map blocked (403). Now searching for secrets and sensitive data:
Now testing remaining endpoints including api/health, Next.js HMR, and POST methods on webhook paths:
Important: CSP header reveals Sentry key, project ID, frame-ancestors (Coast integration). Let me check the JS for more secrets and test a few more paths:
Let me check the security.txt at the well-known path and a few more key paths before compiling findings:
Now I have all the data I need. Let me compile the comprehensive report:
Now let me check existing findings and write confirmed findings:
Now save the learning about unauthenticated endpoint behavior:
Let me update the existing tech stack learning with the new data points:
All data is saved. Let me write a final summary file for the orchestrator:
Final Summary
What I Did
Performed comprehensive unauthenticated probing of https://app.████████.com/ covering all 10 categories from the task brief - 48 endpoints tested without any session cookie. Downloaded and analyzed the 1.87MB JavaScript bundle from assets.████████.com. Tested GraphQL with proper Referer/Origin headers. Attempted source map and pusher auth endpoint access.
What I Found
Returns Real Data (No Auth Required):
| Endpoint | Status | Data |
|---|---|---|
| 'GET /robots.txt' | 200 | 'User-Agent: * Allow: /$ Disallow: /' |
| 'GET /version' | 200 | '[REDACTED_BUILD]' (build number) ⚠️ |
| 'assets.████████.com/vite/assets/index-DfBC4Yx-.js' | 200 | Sentry RELEASE = full git SHA '2c2f0713...' ⚠️ |
| 'assets.████████.com/vite/assets/index-[REDACTED_HASH].js' | 200 | 1.87MB bu... |
Good - task_1 is done. Let me review what was found while task_0 finishes.
task_1 results reviewed. Key findings are low/info severity - no critical unauthenticated data exposure from the cold probe. Waiting for task_0 (authenticated crawl + strip-cookie replay) which is the more impactful test for financial endpoint exposure.
task_1 summary so far:
- 48 endpoints tested cold (no session)
- GraphQL fully protected - 404 without session cookie
- Pusher '/pusher/auth' & '/pusher/channel_auth' confirmed to exist, properly require session
- '/version' leaks build number '[REDACTED_BUILD]' (Low)
- Git SHA '2c2f0713...' exposed in JS bundle via Sentry release (Low)
- No hardcoded secrets in 1.87MB JS bundle
- Source maps blocked (403) - good
- Rails internals ('/rails/info', '/cable', etc.) all 404
- CSRF on '/auth/auth0/callback' working correctly
Waiting for task_0 to...
Sending a focus nudge to keep task_0 on track and avoid over-exploration.
Acknowledged. task_0 received the focus message and is wrapping up the strip-cookie replay tests. Waiting for it to complete - will resume automatically.
Understood - waiting for task_0 to finalize its strip-cookie replay results and write the output file. Will resume automatically when it completes.
I'll start with the mandatory setup steps before diving into testing.
No profiles loaded yet. Let me check existing workspace files and http_history before starting the browser session.
I have a saved session. Let me verify if it's still valid before doing a full re-login.
Session is expired (cookie rotated). Need fresh login via browser handover.
I have fresh cookies. Let me first verify the session then get CSRF token.
Let me try with just the _████████ cookie (no AWSALBTG) as in earlier successful requests:
Let me use the browser session from handover to navigate and capture endpoints.
Good, I have a browser session. Let me navigate to get CSRF token and verify auth works.
Page loaded. I can see CSRF token: '0UQC8z8UgLqCwP5XVev_[REDACTED_TOKEN]'. Now let me extract cookies and test auth.
Now I have fresh cookies. Let me test GraphQL with fresh session cookie and CSRF token:
Session verified. The session cookie rotated - I'll use the latest one. Now let me navigate the app systematically to discover all endpoints using browser intercept.
No browser intercept available. Let me navigate each section manually and capture API endpoints through http_history after each navigation.
Good, dashboard is loaded. Let me navigate all sections and capture XHR traffic via http_history. I'll navigate each section:
I can see Payment sub-navigation. Let me use browser execute script to navigate all sections at once and collect GraphQL operations. First, let me directly call the key GraphQL operations from the browser:
Excellent! I found real financial data. Now I have authenticated responses. Let me test the same endpoints WITHOUT auth cookies to check for unauthenticated access:
The 404 without cookies tells me routing depends on AWSALBTG (ALB sticky session). Let me test with AWSALBTG but no session cookie:
Good - /graphql returns 404 without auth (routing depends on session). Let me now discover REST API endpoints and test Pusher auth. Let me navigate sections and run more GraphQL operations from browser:
Interesting findings! Webhook endpoints have SSRF test payloads. Let me discover the Pusher auth endpoint and navigate more sections:
Let me search for Pusher auth endpoint in the JS and navigate key sections:
Browser session dropped. Let me re-initialize with the saved cookies and search for more endpoints:
Found audit records field name and URL patterns! Let me test more:
Found '/payment_orders' returns 415 (valid route exists!). Let me test it with HTML accept and without auth:
Understood. Let me do all strip-cookie replays now in parallel batches:
Now let me test the HTML endpoints (which worked with auth) without session cookie:
Key finding! Unauthenticated request to '/payment_orders' → 302 redirect to '/auth/auth0'. Let me test all HTML endpoints unauthenticated + test /graphql with the unauth cookie:
Got unauth AWSALBTG cookie. Now test /graphql with unauth _████████ + AWSALBTG:
Now let me run the comprehensive final tests including CSRF bypass test, Pusher auth, and auth/auth0 endpoint:
Let me get fresh cookies from the browser session and run the CSRF bypass test:
Now let me run the key tests in parallel:
- Session validation with fresh cookies
- CSRF bypass test (no CSRF token, no Referer, just session cookie)
- Test Pusher auth with fresh cookies
- Test settings unauthenticated
Session works. Now test CSRF bypass - no CSRF token, no Referer:
403 with no Referer (good security)! Let me test with just session cookie and no Referer (to check if AWSALBTG changes behavior):
Good - 403 without Referer. Now test auth + Referer but NO CSRF token:
All endpoints properly protected! Let me now test GraphQL introspection and collect all remaining data:
Understood. Wrapping up now. Let me compile all findings and write the output files.
Now let me write confirmed findings and update the auth profile:
Now let me write the comprehensive endpoint discovery summary:
Let me update the learning and check for existing confirmed findings:
The existing learning shows '/pusher/auth' returns 403 (confirmed endpoint). Let me update it:
Let me check existing confirmed findings file:
Good - existing findings are about version/git SHA disclosure. My auth replay testing confirms NO unauthenticated data exposure. Let me provide the final summary.
Summary
What I Did
-
Recovered authentication via browser handover login (ORG 1 credentials). Previous session was expired; obtained fresh '_████████' + 'AWSALBTG' + 'X-CSRF-Token' credentials.
-
Verified session with 'POST /graphql' (ProfileHome query) → 200 OK, confirmed user: ████████ / [REDACTED_EMAIL]
-
Discovered all major endpoints by executing GraphQL operations from the authenticated browser session across all app sections:
- Payment Orders (61 total), Transactions, Internal Accounts (5), Counterparties (84), Ledgers (5), Connections (3), Webhooks (15), API Keys (1), Org Users (1), Ledg...
Both agents complete. All data reviewed. Now rendering the final summary.
65 endpoints tested across two parallel agents. Here's the bottom line:
No significant unauthenticated data exposure found. The authentication layer on ████████ is well-implemented. Every financial endpoint - payment orders, transactions, accounts, counterparties, ledgers, webhooks, API keys, org users - is properly protected. Unauthenticated requests either receive a '302 → /auth/auth0' redirect (HTML routes) or a '404 path not found' (GraphQL), the latter being a security-positive design where Rails only maps '/graphql' into the routing table when a valid session exists.
Confirmed findings requiring action:
| Severity | Finding | Endpoint |
|---|---|---|
| Low | Version number disclosed without auth | 'GET /version' → '[REDACTED_BUILD]' |
| Low | Full git commit SHA in p... |