22 KiB
Security Audit Report — app.closebot.com
Date: February 7, 2026
Auditor: Clawdbot Security Scanner
Scope: app.closebot.com, api.closebot.com, closebot.com
Authorization: Fully authorized pentest by site owner (Jake Shore)
1. Executive Summary
Severity Matrix
| Severity | Count | Findings |
|---|---|---|
| 🔴 CRITICAL | 1 | API CORS wildcard Access-Control-Allow-Origin: * on authenticated endpoints |
| 🟠 HIGH | 3 | Missing security headers on API, Azure infrastructure info leak, No rate limiting on API |
| 🟡 MEDIUM | 4 | WordPress readme/license exposed, NEXT_LOCALE cookie lacks Secure flag, API Azure AppId leak, /bot endpoint method disclosure |
| 🔵 LOW | 3 | WordPress version exposed, Clerk auth status header leak, Build ID exposed in 404 pages |
| ℹ️ INFO | 6 | Tech stack details, positive findings |
Overall Risk Rating: HIGH
The most critical finding is that api.closebot.com has Access-Control-Allow-Origin: * on ALL endpoints, including authenticated ones like /bot, /bot/list, /bot/create, /bot/config, /bot/settings, /lead, /agency. This is the same class of vulnerability found in SuperFunnels. While Access-Control-Allow-Credentials is NOT set (which prevents cookie-based CSRF), any token-based auth (Bearer tokens) sent from JS is still vulnerable to being used in cross-origin attacks if tokens are predictable or leaked.
2. Tech Stack
| Component | Technology | Details |
|---|---|---|
| Frontend (app) | Next.js (App Router) | Build ID: SJe3XKo4eqvdUfxjtlLi9, deployment: dpl_9XCbPqSSm7KFrRoZoDtTN7Cu7QhM |
| Frontend Hosting | Vercel | IAD1 region (us-east-1), Vercel Security Checkpoint enabled |
| Auth Provider | Clerk | Headers: x-clerk-auth-status, x-clerk-auth-reason |
| API Backend | ASP.NET (Kestrel) | Running on Azure App Service |
| API Hosting | Azure App Service | cb-api-zarqcgo3sph6q.azurewebsites.net (West US 2) |
| Marketing Site | WordPress 6.9.1 | Hosted on Kinsta, behind Cloudflare |
| CDN (marketing) | Cloudflare | CF-Ray headers present |
| DNS | GoDaddy | ns77.domaincontrol.com, ns78.domaincontrol.com |
| SSL | Let's Encrypt (R13) | Valid Feb 5 – May 6, 2026 |
| i18n | Multi-language | EN, ES, PT, NL supported |
Subdomain Map
| Subdomain | Status | Resolves To |
|---|---|---|
app.closebot.com |
✅ Active | Vercel (592229a97db57f91.vercel-dns-017.com) |
api.closebot.com |
✅ Active | Azure (cb-api-zarqcgo3sph6q.azurewebsites.net → 20.115.232.12) |
www.closebot.com |
✅ Redirect | → closebot.com (Cloudflare 162.159.134.42) |
closebot.com |
✅ Active | Cloudflare/Kinsta WordPress |
admin.closebot.com |
❌ No DNS | - |
dashboard.closebot.com |
❌ No DNS | - |
ws.closebot.com |
❌ No DNS | - |
mail.closebot.com |
❌ No DNS | - |
staging.closebot.com |
❌ No DNS | - |
dev.closebot.com |
❌ No DNS | - |
DNS Records
- TXT: Google site verification (
A_X4u_WKhr2Mp6maxNXC71DUBr-RlWzxCjrvyxnVrZo), Microsoft verification (MS=ms24389368) - MX: None configured (no email hosting on root domain)
- NS: GoDaddy (
ns77/ns78.domaincontrol.com)
3. HTTP Security Headers
app.closebot.com (Vercel/Next.js)
| Header | Status | Value |
|---|---|---|
Strict-Transport-Security |
✅ Present | max-age=63072000 (~2 years) |
Content-Security-Policy |
❌ MISSING | Not set |
X-Frame-Options |
❌ MISSING | Not set |
X-Content-Type-Options |
❌ MISSING | Not set |
X-XSS-Protection |
❌ MISSING | Not set (deprecated, but still recommended) |
Referrer-Policy |
❌ MISSING | Not set |
Permissions-Policy |
❌ MISSING | Not set |
X-Powered-By |
⚠️ Leaking | Next.js |
Server |
⚠️ Leaking | Vercel |
Severity: HIGH — Missing CSP, X-Frame-Options, and X-Content-Type-Options on the frontend.
api.closebot.com (Azure/Kestrel)
| Header | Status | Value |
|---|---|---|
Strict-Transport-Security |
❌ MISSING | Not set |
Content-Security-Policy |
❌ MISSING | Not set |
X-Frame-Options |
❌ MISSING | Not set |
X-Content-Type-Options |
❌ MISSING | Not set |
X-XSS-Protection |
❌ MISSING | Not set |
Referrer-Policy |
❌ MISSING | Not set |
Permissions-Policy |
❌ MISSING | Not set |
Server |
⚠️ Leaking | Kestrel |
Request-Context |
⚠️ Leaking | appId=cid-v1:1593e7a7-a705-4f69-977e-49c3fa1d0aa3 |
x-ms-middleware-request-id |
⚠️ Leaking | 00000000-0000-0000-0000-000000000000 |
Severity: HIGH — API has ZERO security headers. No HSTS, no CSP, nothing.
closebot.com (WordPress/Cloudflare)
| Header | Status | Value |
|---|---|---|
X-Content-Type-Options |
✅ Present | nosniff |
Strict-Transport-Security |
❌ MISSING | Not set |
Content-Security-Policy |
❌ MISSING | Not set |
X-Frame-Options |
❌ MISSING | Not set |
Referrer-Policy |
❌ MISSING | Not set |
Permissions-Policy |
❌ MISSING | Not set |
4. CORS Analysis — 🔴 CRITICAL
api.closebot.com — WILDCARD CORS ON ALL ENDPOINTS
This is the #1 finding of the entire audit.
| Endpoint | Origin Tested | ACAO Header | Result |
|---|---|---|---|
/ (root) |
https://evil.com |
* |
🔴 OPEN |
/ (root) |
null |
* |
🔴 OPEN |
/ (root) |
https://evil.closebot.com |
* |
🔴 OPEN |
/bot |
https://evil.com |
* |
🔴 OPEN |
/bot (OPTIONS) |
https://evil.com |
* |
🔴 OPEN |
| Preflight | Any | Allows Authorization,Content-Type |
🔴 OPEN |
Key facts:
Access-Control-Allow-Origin: *is returned for ANY origin- Preflight
OPTIONSreturnsAccess-Control-Allow-Headers: Authorization,Content-Type— meaning cross-origin JS can send auth headers Access-Control-Allow-Credentialsis NOT set (mitigating cookie-based attacks)- However, if the API uses Bearer tokens (JWT) passed via
Authorizationheader, any malicious website can make authenticated API calls if it obtains the token
Impact:
- If a user visits a malicious site while logged into Closebot, and the malicious site can obtain/guess the auth token, it can make full API calls to read/modify bot data, leads, agency settings
- The preflight allows
Authorizationheader, so even "complex" requests are permitted cross-origin
Recommendation: Replace * with an explicit allowlist: https://app.closebot.com, https://closebot.com
app.closebot.com — No CORS headers on most responses
The frontend (Vercel/Next.js) does NOT return CORS headers on normal pages. The 404 page returns Access-Control-Allow-Origin: * but this is a static error page and lower risk.
5. Cookie/Session Analysis
app.closebot.com Cookies
| Cookie | Secure | HttpOnly | SameSite | Domain | Notes |
|---|---|---|---|---|---|
NEXT_LOCALE |
❌ No | ❌ No | Lax |
/ path |
⚠️ Language preference — missing Secure flag |
| Clerk session cookies | Not directly observed (behind Vercel checkpoint) | — | — | — | Clerk typically handles this well |
Severity: MEDIUM — NEXT_LOCALE cookie is set without Secure flag, allowing it to be sent over HTTP if user visits http:// URL. While HSTS mitigates this on the app domain, it's still a best practice violation.
api.closebot.com Cookies
| Cookie | Secure | HttpOnly | SameSite | Domain | Notes |
|---|---|---|---|---|---|
TiPMix |
✅ Yes | ✅ Yes | None |
.api.closebot.com |
Azure routing cookie |
x-ms-routing-name |
✅ Yes | ✅ Yes | None |
.api.closebot.com |
Azure routing — value: self |
Note: SameSite=None on Azure routing cookies means they're sent cross-site. Combined with the CORS *, this is concerning — though these are infrastructure cookies, not auth tokens.
closebot.com Cookies
| Cookie | Secure | HttpOnly | SameSite | Domain |
|---|---|---|---|---|
__cf_bm |
✅ Yes | ✅ Yes | None |
.closebot.com |
Cloudflare bot management cookie — properly secured.
Auth Mechanism
- Clerk is used for authentication (confirmed by
x-clerk-auth-statusandx-clerk-auth-reasonheaders) - Unauthenticated requests get
x-clerk-auth-status: signed-outandx-clerk-auth-reason: session-token-and-uat-missing - Root
/redirects to/login?redirect_url=%2F(307 redirect) /registerexists and returns 200 — open registration is available
6. API/Endpoint Map
app.closebot.com (Vercel/Next.js)
| Path | Status | Notes |
|---|---|---|
/ |
307 | Redirects to /login |
/login |
200 | Login page (Clerk) |
/register |
200 | Registration page (open signup) |
/signup |
404 | Not used |
/pricing |
403* | Protected (behind Vercel checkpoint after rate limit) |
/settings |
403* | Protected |
/billing |
403* | Protected |
/account |
403* | Protected |
/bots |
403* | Protected |
/conversations |
403* | Protected |
/analytics |
403* | Protected |
/docs |
403* | Protected |
/.env |
404 | ✅ Not exposed |
/.git |
404 | ✅ Not exposed |
/robots.txt |
404 | No robots.txt |
/sitemap.xml |
404 | No sitemap |
/.well-known/security.txt |
404 | No security.txt |
*403 responses are from Vercel Security Checkpoint (bot challenge), not actual authorization blocks.
api.closebot.com (Azure/Kestrel)
| Path | Status | Methods | Notes |
|---|---|---|---|
/bot |
401/405 | GET, POST | Core bot endpoint — requires auth |
/bot/list |
401 | — | List bots |
/bot/create |
401 | — | Create bot |
/bot/all |
401 | — | All bots |
/bot/settings |
401 | — | Bot settings |
/bot/config |
401 | — | Bot config |
/lead |
401 | — | Lead management |
/agency |
401 | — | Agency management |
/swagger |
301 | — | Swagger redirect (leads to 404 — likely disabled in prod) |
/ |
404 | — | No root handler |
| All other paths | 404 | — | — |
Severity: MEDIUM — The /bot endpoint returns Allow: GET, POST in the 405 response, revealing accepted HTTP methods. The /swagger 301 redirect suggests Swagger UI was enabled at some point.
closebot.com (WordPress)
| Path | Status | Notes |
|---|---|---|
/wp-admin |
301 | Redirects to login — exposed |
/wp-login.php |
200 | Login page accessible |
/wp-json |
200 | REST API root — accessible |
/wp-json/wp/v2/users |
401 | User enumeration blocked ✅ |
/.env |
403 | Blocked ✅ |
/xmlrpc.php |
403 | Blocked ✅ |
/wp-config.php |
403 | Blocked ✅ |
/readme.html |
200 | ⚠️ Exposed — WordPress readme |
/license.txt |
200 | ⚠️ Exposed — WordPress license |
/feed/ |
200 | ⚠️ Exposes WordPress version 6.9.1 |
7. Client-Side Analysis
Findings from HTML Source
-
Vercel Security Checkpoint — app.closebot.com serves a JS-based browser verification challenge (Astro framework) before allowing access. This is an effective bot protection layer.
-
Next.js Build ID exposed:
SJe3XKo4eqvdUfxjtlLi9— visible in error pages and static chunk URLs. Low risk but provides deployment fingerprinting. -
Deployment ID exposed:
dpl_9XCbPqSSm7KFrRoZoDtTN7Cu7QhM— in chunk URLs. -
Internationalization: Site supports EN, ES, PT, NL via
x-matched-path: /[locale]/loginrouting. -
Clerk Auth Headers Leaked in Every Response:
x-clerk-auth-status: signed-outx-clerk-auth-reason: session-token-and-uat-missing
These headers confirm the auth provider and current auth state to any observer.
Source Maps
- All
_next/staticresources are behind Vercel Security Checkpoint (return 403 challenge page to curl) - Could not confirm/deny source map availability without browser access
- Recommendation: Ensure
.mapfiles are not deployed to production
JS Bundles Analysis
- Could not analyze JS bundles directly due to Vercel Security Checkpoint blocking curl requests
- The checkpoint uses a Web Worker-based challenge system
- Recommendation: Verify no API keys, Firebase configs, or secrets are hardcoded in client bundles
8. Injection Test Results
Host Header Injection
- app.closebot.com: ✅ Protected — Vercel returns 404
DEPLOYMENT_NOT_FOUNDfor invalid Host headers - X-Forwarded-Host: ⚠️ Accepted without error (200 response) — Vercel passes it through to Next.js
CRLF Injection
- app.closebot.com: ✅ Not vulnerable — URL-encoded
%0d%0ais preserved inLinkheader as-is (not decoded), no header injection
Path Traversal
- Standard path traversal payloads return 404 from Next.js catch-all router — not vulnerable
SQL Injection / XSS
- Could not test input fields directly (behind Vercel Security Checkpoint)
- API endpoints return 401 without processing input — auth layer prevents unauthenticated injection testing
- Recommendation: Test authenticated injection scenarios during development
9. Rate Limiting Results
app.closebot.com
| Endpoint | Requests | All Status Codes | Rate Limited? |
|---|---|---|---|
/login |
50 rapid | All 200 |
🔴 NO |
After approximately 50+ requests, Vercel Security Checkpoint started returning 403 challenges — this is Vercel's built-in protection, not application-level rate limiting.
Note: Vercel's checkpoint eventually kicked in (HTTP 403 with x-vercel-mitigated: challenge), providing some protection, but this is infrastructure-level, not application-level rate limiting.
api.closebot.com
| Endpoint | Requests | All Status Codes | Rate Limited? |
|---|---|---|---|
/ |
50 rapid | All 404 |
🔴 NO |
Severity: HIGH — No rate limiting on the API. This means:
- Brute-force attacks on auth tokens are possible
- API abuse/scraping is unrestricted
- DDoS amplification risk
Recommendation: Implement rate limiting (e.g., Azure API Management, custom middleware, or Cloudflare in front of the API).
10. Auth/Firebase Analysis
Authentication System: Clerk
- Provider: Clerk (not Firebase)
- Open Registration: Yes —
/registerreturns 200 - Login:
/loginwith redirect support - Auth tokens: Likely JWT via Clerk (standard Clerk flow)
- Session management: Clerk handles sessions via
__sessioncookie and/or Bearer tokens
No Firebase Found
/__/firebase/init.json→ 404- No Firebase references detected in accessible HTML/JS
- Not applicable for Firebase-specific testing
11. Third-Party Risk
External Scripts (from HTML source)
Due to Vercel Security Checkpoint, detailed JS bundle analysis was limited. From what was visible:
- Clerk — Authentication provider (trusted, SOC 2 compliant)
- Next.js — React framework (trusted)
- Vercel — Hosting platform (trusted)
WordPress Third-Party
- Cloudflare — CDN and bot protection
- Kinsta — WordPress hosting
SRI (Subresource Integrity)
- Could not verify SRI on JS bundles due to Vercel checkpoint
- Recommendation: Ensure all third-party scripts have SRI hashes
12. Infrastructure Notes
Origin IP Exposure
| Domain | Behind CDN? | Origin Exposed? |
|---|---|---|
app.closebot.com |
Vercel Edge | ✅ Protected (Vercel DNS) |
api.closebot.com |
❌ NO CDN | 🔴 YES — 20.115.232.12 (Azure direct) |
closebot.com |
Cloudflare | ✅ Protected |
Severity: HIGH — api.closebot.com resolves directly to an Azure App Service IP with no CDN/WAF in front. The full Azure hostname cb-api-zarqcgo3sph6q.azurewebsites.net is exposed via DNS CNAME chain.
Azure Information Leakage
- App ID:
cid-v1:1593e7a7-a705-4f69-977e-49c3fa1d0aa3(viaRequest-Contextheader) - Azure hostname:
cb-api-zarqcgo3sph6q.azurewebsites.net - Datacenter:
waws-prod-mwh-117(West US 2, Microsoft West Hub) - Server: Kestrel (ASP.NET)
- Routing cookies: TiPMix (Azure traffic routing)
SSL/TLS
| Property | Value |
|---|---|
| Certificate | Let's Encrypt R13 |
| Valid From | Feb 5, 2026 |
| Valid Until | May 6, 2026 |
| Subject | CN=app.closebot.com |
| SANs | app.closebot.com only |
| HSTS | ✅ max-age=63072000 (app only) |
| HSTS Preload | ❌ Not in preload list |
13. Positive Findings ✅
- Vercel Security Checkpoint — Effective bot/scraping protection on the frontend
- Clerk Authentication — Industry-standard auth provider, properly handling session states
- No sensitive files exposed —
.env,.git,wp-config.phpall blocked - WordPress user enumeration blocked —
/wp-json/wp/v2/usersreturns 401 - XML-RPC disabled — Returns 403
- HSTS on app.closebot.com — 2-year max-age
- Host header injection blocked — Vercel properly rejects invalid hosts
- CRLF injection blocked — Properly encoded
- No admin/staging subdomains exposed — Clean subdomain surface
- WordPress .env/wp-config blocked — Server-level blocks in place
- Azure API cookies properly secured — Secure, HttpOnly flags set
- Cloudflare protecting WordPress — Bot management, edge caching
14. Recommendations
🔴 CRITICAL — Fix Immediately
1. API CORS Wildcard (Access-Control-Allow-Origin: *)
Impact: Any website can make cross-origin requests to your API, including authenticated endpoints
Fix:
// In your ASP.NET API startup/program.cs
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
{
policy.WithOrigins(
"https://app.closebot.com",
"https://closebot.com"
)
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
});
});
🟠 HIGH — Fix This Week
2. Add Security Headers to API (api.closebot.com)
// Middleware or web.config
app.Use(async (context, next) =>
{
context.Response.Headers.Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains");
context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
context.Response.Headers.Add("X-Frame-Options", "DENY");
context.Response.Headers.Add("Referrer-Policy", "strict-origin-when-cross-origin");
context.Response.Headers.Add("Content-Security-Policy", "default-src 'none'");
context.Response.Headers.Remove("Server");
context.Response.Headers.Remove("Request-Context");
context.Response.Headers.Remove("x-ms-middleware-request-id");
await next();
});
3. Put API Behind CDN/WAF
- Add Cloudflare or Azure Front Door in front of
api.closebot.com - Hide the origin Azure IP
- Get DDoS protection and rate limiting
4. Implement API Rate Limiting
// ASP.NET rate limiting middleware
builder.Services.AddRateLimiter(options =>
{
options.AddFixedWindowLimiter("api", opt =>
{
opt.Window = TimeSpan.FromMinutes(1);
opt.PermitLimit = 60;
opt.QueueLimit = 0;
});
});
🟡 MEDIUM — Fix This Sprint
5. Add Security Headers to app.closebot.com
In next.config.js:
const securityHeaders = [
{ key: 'Content-Security-Policy', value: "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://*.clerk.accounts.dev; style-src 'self' 'unsafe-inline';" },
{ key: 'X-Frame-Options', value: 'DENY' },
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
{ key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' },
];
module.exports = {
headers: async () => [{ source: '/:path*', headers: securityHeaders }],
poweredByHeader: false, // Remove X-Powered-By: Next.js
};
6. Remove WordPress readme.html and license.txt
# On WordPress server
rm /path/to/wordpress/readme.html
rm /path/to/wordpress/license.txt
7. Hide Azure Infrastructure Headers
Remove Request-Context and x-ms-middleware-request-id headers from API responses.
8. Add Secure Flag to NEXT_LOCALE Cookie
In Next.js middleware or cookie configuration, ensure Secure flag is set.
🔵 LOW — Fix When Convenient
9. Add security.txt
Create /.well-known/security.txt with responsible disclosure contact.
10. Add robots.txt
Even if you don't want indexing, an explicit robots.txt is good practice.
11. Hide WordPress Version
// In functions.php
remove_action('wp_head', 'wp_generator');
12. Remove Clerk Auth Headers from Responses
Configure Clerk middleware to not expose x-clerk-auth-status and x-clerk-auth-reason to external responses.
13. HSTS Preload
Submit app.closebot.com to the HSTS preload list and add includeSubDomains; preload to the HSTS header.
Appendix: Raw Test Data
CORS Test Results (api.closebot.com)
Origin: https://evil.com → Access-Control-Allow-Origin: *
Origin: null → Access-Control-Allow-Origin: *
Origin: https://evil.closebot.com → Access-Control-Allow-Origin: *
OPTIONS (preflight) → Access-Control-Allow-Origin: *, Allow-Headers: Authorization,Content-Type
API Endpoint Discovery Summary
Authenticated (401): /bot, /bot/list, /bot/create, /bot/all, /bot/settings, /bot/config, /lead, /agency
Redirect (301): /swagger
Not Found (404): everything else
Rate Limiting Test (50 rapid requests)
app.closebot.com/login: 200 200 200 200 200 ... (all 200, then Vercel checkpoint kicks in)
api.closebot.com/: 404 404 404 404 404 ... (all 404, never rate limited)